#include<linux/module>
#include<linux/kernel>
#include<linux/platform_device.h>

int major=11;
int minor=0;
int mychar_num=1;

#define BUF_LEN 100

struct mychar_dev{
	
	struct cdev mydev;
	char mychar_buf[BUF_LEN];
	
	unsigned int curlen;
	
	wait_queue_head_t rq;
	wait_queue_head_t wq;
}

struct mychar_dev* pgmydev=NULL;


int mychar_open(struct inode* pnode,struct file* pfile){
	struct mychar_dev* pgmydev=NULL;
	pgmydev=(struct mychar_dev*)(continer_of(pnode->i_cdev,struct mychar_dev,mydev));
	pfile->private_data=(void*)pgmydev;
	
	return 0;
}
int mychar_close(struct inode* pnode,struct file* pfile){
	
	return 0;
}
ssize_t mychar_read(struct file* pfile,char __user* puser,size_t count,loff_t* p_pos){
	struct mychar_dev* pgmydev=(struct mychar_dev*)pfile->private_data;
	int ret;
	
	int size=0;
	
	if(pgmydev->curlen<=0){
		//这个时候是不能读的
		
		//现在来判断我们打开fd的时候的权限
		if(pfile->f_flags&O_NONBLOCK){
			//这里是不能读直接返回
			return -1;
		}else{
			//阻塞
			printk("NO Data read\n");
			ret=wait_event_interruptible(pgmydev->rq,pgmydev->curlen>0);
			if(ret){
				printk("wake up by signal\n");
				return -ERESTARTSYS;
			}	
		}
	}
	if(count>=pgmydev->curlen){
		size=pgmydev->curlen;
	}else{
		
		size=count;
	}
	ret=copy_to_user(puser,pgmydev->mychar_buf,size);
	if(ret){
		printk("copy failed\n");
		return -1;
	}
	memcpy(pgmydev->mychar_buf,pgmydev->mychar_buf+size,pgmydev->curlen-size);
	pgmydev->curlen=pgmydev->curlen-size;
	wait_up(&pgmydev->wq);
	return 0;
	
}
ssize_t mychar_write(struct file* pfile,char __user* puser,size_t count,loff_t* p_pos){
	struct mychar_dev* pgmydev=(struct mychar_dev*)pfile->private_data;
	int size=0;
	int ret=0;
	if(pgmydev->curlen>=pgmydev->BUF_LEN){
		if(pfile->f_flags&O_NONBLOCK){
			//这里是不能写直接返回
			return -1;
		}else{
			//阻塞
			printk("NO Data read\n");
			ret=wait_event_interruptible(pgmydev->wq,pgmydev->curlen<pgmydev->BUF_LEN);
			if(ret){
				printk("wake up by signal\n");
				return -ERESTARTSYS;
			}	
		}
	}
	if(count>=pgmydev->BUF_LEN-pgmydev->curlen){
		
		size=pgmydev->BUF_LEN-pgmydev->curlen;
	}else{
		size=count;
	}
	
	ret=copy_from_user(pgmydev->mychar_buf+curlen,puser,size);
	if(ret){
		printk("copy failed\n");
		return -1;
	}
	pgmydev->curlen+=size;
	wait_up(&pgmydev->rq);
	return 0;
}

int mychar_poll(struct file* pfile,poll_table* ptb){
	unsigned int mask=0;
	struct mychar_dev* pgmydev=(struct mychar_dev*)pfile->private_data;
	
	poll_wait(pfile,&pgmydev->rq,ptb);
	poll_wait(pfile,&pgmydev->wq,ptb);
	
	if(pgmydev-curlen>0){
		mask |= POLLIN|POLLRDNORM;
	}
	if(pgmydev->curlen<pgmydev->BUF_LEN){
		mask |= POLLOUT|POLLWRNORM;
	}
	return mask;
}

struct file_operations myops{
	.owner=THIS_MODULE,
	.open=mychar_open;
	.release=mychar_close,
	.read=mychar_read,
	.write=mychar_write,
	.poll=mychar_poll,
	
}


int __init mychar_init(void){
	int ret=0;
	dev_t devno=MKDEV(major,minor);
	ret=register_chrdev_region(devno,mychar_num,"mychar");
	if(ret){
		
		ret=alloc_chrdev_region(&devno,mychar_num,"mychar");
		if(ret){
			printk("register devno failed\n");
			return -1;
		}
		major=MAJOR(devno);
	}
	
	pgmydev=(struct mychar_dev*)kmalloc(sizeof(struct mychar_dev),GPF_KERNEL);
	if(NULL==pgmydev){
		
		printk("kmalloc failed\n");
		unregister_chrdev_region(devno,mychar_num);
		return -1;
	}
	memset(pgmydev,0,sizeof(struct mychar_dev));
	
	cdev_init(&pgmydev->mydev,&myops);
	pgmydev->mydev.owner=THIS_MODULE;
	
	cdev_add(&pgmydev->mydev,devno,mychar_num);
	
	init_waitqueue_head(&pgmydev->rq);
	init_waitqueue_head(&pgmydev->wq);

	return 0;
}

int __exit mychar_exit(void){
	
	dev_t devno=MKDEV(major,minor);
	unregister_chrdev_region(devno,mychar_num);
	cdev_del(&pgmydev->mydev);
	del_timer(&pgmydev->timer);
	kfree(pgmydev);
	pgmydev=NULL;
	return 0;
}

MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);